package com.archtecture.control.facades;

import java.util.List;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import com.archtecture.control.enums.Mensagem;
import com.archtecture.control.enums.Severidade;
import com.archtecture.control.exceptions.MensagemException;
import com.archtecture.control.models.ModelAb;
import com.archtecture.control.utils.JPQLFactory;

@Stateless(name = "GenericPersistenceFacadeBean")
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
@TransactionManagement(TransactionManagementType.CONTAINER)
public class GenericPersistenceFacadeBean implements GenericPersistenceFacadeRemote {

	@PersistenceContext(unitName = "ARC_PU")
	EntityManager	manager;

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public <Model extends ModelAb> Model atualizar(final Model pModel) throws MensagemException {

		if (pModel.getCodigo() == null) {
			throw new MensagemException(Severidade.ERROR, Mensagem.ERRO_ENTIDADE_SEM_CODIGO);
		}

		manager.merge(pModel);
		manager.flush();
		return pModel;
	}

	@SuppressWarnings("unchecked")
	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public <Model extends ModelAb> Model carregar(final Model pModel) throws MensagemException {
		
		if (pModel.getCodigo() == null) {
			throw new MensagemException(Severidade.ERROR, Mensagem.ERRO_ENTIDADE_SEM_CODIGO);
		}
		
		final String jpqlString = JPQLFactory.montarConsultaJPQLResultadoUnico(pModel);
		final Query query = manager.createQuery(jpqlString);
		final Model model = (Model) query.getSingleResult();
		return model;
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public <Model extends ModelAb> void excluir(final Model pModel) throws MensagemException {

		try {
			manager.remove(manager.find(pModel.getClass(), pModel.getCodigo()));
			manager.flush();
		} catch (final PersistenceException pex) {
			pex.printStackTrace();
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public <Model> List<Model> executarJPQLResultadoMultiplo(final String jpql) {
		final Query query = manager.createQuery(jpql);
		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	@Override
	public <Model> Model executarJPQLResultadoUnico(final String jpql) throws MensagemException {
		final Query query = manager.createQuery(jpql);

		final List<Model> models = query.getResultList();

		if (models.size() > 1) {
			throw new MensagemException(Severidade.ERROR, Mensagem.ERRO_MULTIPLOS_RESULTADOS_NA_PESQUISA_UNICA);
		}

		for (final Model model : models) {
			return model;
		}

		return null;
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public <Model extends ModelAb> Model inserir(final Model pModel) throws MensagemException {

		if (pModel.getCodigo() != null) {
			throw new MensagemException(Severidade.ERROR, Mensagem.ERRO_ENTIDADE_COM_CODIGO);
		}

		try {
			manager.persist(pModel);
		} catch (final Exception e) {
			throw new MensagemException(e);
		}
		return pModel;
	}

	@Override
	public <Model extends ModelAb> List<Model> pesquisarLista(final Model pModel) throws MensagemException {
		final String jpqlString = JPQLFactory.montarConsultaJPQLMultiplosResultados(pModel);
		return executarJPQLResultadoMultiplo(jpqlString);
	}

	@Override
	public <Model extends ModelAb> Model pesquisarUnico(final Model pModel) throws MensagemException {
		final String jpqlString = JPQLFactory.montarConsultaJPQLMultiplosResultados(pModel);
		return executarJPQLResultadoUnico(jpqlString);
	}
}